package highlighter.tests;

import static org.junit.Assert.*;
import org.junit.Test;
import highlighter.parser.*;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java_cup.runtime.Symbol;

public class LexerTest {
	
	
	@Test
	public void ifStmt() throws IOException {
		String prog = " if (i < j) {} else {};";

		List<Symbol> expectedTokens = new ArrayList<Symbol>();
		expectedTokens.add(new Symbol(sym.K_IF));
		expectedTokens.add(new Symbol(sym.LP));
		expectedTokens.add(new Symbol(sym.ID, "i"));
		expectedTokens.add(new Symbol(sym.LT));
		expectedTokens.add(new Symbol(sym.ID, "j"));
		expectedTokens.add(new Symbol(sym.RP));
		expectedTokens.add(new Symbol(sym.LB));
		expectedTokens.add(new Symbol(sym.RB));
		expectedTokens.add(new Symbol(sym.K_ELSE));
		expectedTokens.add(new Symbol(sym.LB));
		expectedTokens.add(new Symbol(sym.RB));
		expectedTokens.add(new Symbol(sym.SEMI));

		List<Symbol> tokens = runLexer(prog);

		List<String> errors = compareResults(expectedTokens, tokens);
		assertTrue(errors.toString(), errors.isEmpty());
	}

	@Test
	public void printStmt() throws IOException {
		String prog = "while ( i > 0 ) { i = i - 1; }";

		List<Symbol> expectedTokens = new ArrayList<Symbol>();
		expectedTokens.add(new Symbol(sym.K_WHILE));
		expectedTokens.add(new Symbol(sym.LP));
		expectedTokens.add(new Symbol(sym.ID, "i"));
		expectedTokens.add(new Symbol(sym.GT));
		expectedTokens.add(new Symbol(sym.NUMBER, 0));
		expectedTokens.add(new Symbol(sym.RP));
		expectedTokens.add(new Symbol(sym.LB));
		expectedTokens.add(new Symbol(sym.ID, "i"));
		expectedTokens.add(new Symbol(sym.EQ));
		expectedTokens.add(new Symbol(sym.ID, "i"));
		expectedTokens.add(new Symbol(sym.MINUS));
		expectedTokens.add(new Symbol(sym.NUMBER, 1));
		expectedTokens.add(new Symbol(sym.SEMI));
		expectedTokens.add(new Symbol(sym.RB));

		List<Symbol> tokens = runLexer(prog);

		List<String> errors = compareResults(expectedTokens, tokens);
		assertTrue(errors.toString(), errors.isEmpty());
	}
	
	private List<Symbol> runLexer(String sourceCode) throws IOException {

		Reader reader = new StringReader(sourceCode);
		HighlighterLexer lexer = new HighlighterLexer(reader);

		List<Symbol> tokens = new ArrayList<Symbol>();

		Symbol token = null;
		while (true) {
			token = lexer.next_token();
			if (token.sym == sym.EOF) {
				break;
			}
			tokens.add(token);
		}

		return tokens;
	}

	private List<String> compareResults(List<Symbol> expectedTokens,
			List<Symbol> actualTokens) {
		return compareResults(expectedTokens, actualTokens, true);
	}

	private List<String> compareResults(List<Symbol> expectedTokens,
			List<Symbol> actualTokens, boolean compareValues) {

		List<String> errors = new ArrayList<String>();

		if (expectedTokens.size() != actualTokens.size()) {
			errors.add("different size  expected " + expectedTokens.size()
					+ " found " + actualTokens.size());
			return errors;
		}
		for (int i = 0; i < expectedTokens.size(); i++) {
			Symbol t1 = expectedTokens.get(i);
			Symbol t2 = actualTokens.get(i);
			if (t1.sym != t2.sym) {
				errors.add("different tokens expected type#" + t1.sym
						+ " found type#" + t2.sym);
				return errors;
			}
			if (compareValues) {
				if (t1.value != null) {
					if (!t1.value.equals(t2.value)) {
						errors.add("different values for token type#" + t1.sym
								+ " expected " + t1.value + " found "
								+ t2.value);
						return errors;
					}
				} else {
					if (t2.value != null) {
						errors.add("different values for token type#" + t1.sym
								+ " expected " + t1.value + " found "
								+ t2.value);
						return errors;
					}
				}
			}
		}

		return errors;
	}

}
